package com.xike.pdfdemo.util;

import com.itextpdf.text.DocumentException;
import com.xike.pdfdemo.config.PdfBoxConfig;
import com.xike.pdfdemo.dto.Message;
import com.xike.pdfdemo.entity.DictData;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.PDResources;
import org.apache.pdfbox.pdmodel.font.PDFont;
import org.apache.pdfbox.pdmodel.font.PDType0Font;
import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm;
import org.apache.pdfbox.pdmodel.interactive.form.PDTextField;
import org.springframework.core.io.ClassPathResource;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * Pdfbox
 * 文本域 + 内容流 方式
 * @author xike
 * @date 2023/3/20
 */
@Component
public class PdfBoxUtils {

    final static String FONT_SEGUISYM = "fonts/seguisym.ttf";
    final static String FONT_SIMHEI = "fonts/simhei.ttf";
    final static String TEMPLATE = "templates/applying_for_volunteer_service_form_pdfBox.pdf";

    public static void generatePdf(OutputStream os, Message message, List<String> pickVolunteers, Map<String, List<DictData>> allVolunteers, List<DictData> volunteerTypes) throws IOException, DocumentException {
        InputStream templateInputStream = new ClassPathResource(TEMPLATE).getInputStream();
        try (PDDocument pdfDocument = PDDocument.load(templateInputStream)) {

            // 1：使用文本域填充模板 -- 基础数据
            buildBasicData(pdfDocument,message);

            // 2：使用内容流写入数据 -- 特殊数据
            // 配置类型
            buildVolunteerTypes(pdfDocument,message.getVolunteerType(),volunteerTypes);
            // 配置志愿服务
            buildAllVolunteers(pdfDocument,allVolunteers,pickVolunteers);
            // 特殊复选框
            buildCheckBox(pdfDocument);

            // 3：保存文档
            pdfDocument.save(os);
        }
    }

    /**
     * 基本数据填充模板
     * @param pdfDocument
     * @param message
     * @throws IOException
     * @throws DocumentException
     */
    private static void buildBasicData(PDDocument pdfDocument, Message message) throws IOException {
        PDAcroForm acroForm = pdfDocument.getDocumentCatalog().getAcroForm();

        if (acroForm != null) {
            PDResources resources = acroForm.getDefaultResources();
            //中文字体
            InputStream inputStream = new ClassPathResource(FONT_SIMHEI).getInputStream();
            PDFont font = PDType0Font.load(pdfDocument, inputStream);
            String fontName = resources.add(font).getName();
            String defaultAppearance = "/" + fontName + " 9.5 Tf 0 g";

            Map<String,String> map = new HashMap<>();
            map.put("name",message.getName());
            map.put("date",message.getDate());
            map.put("phone",message.getPhone());
            map.put("email",message.getEmail());
            map.put("school",message.getSchool());
            map.put("reason", message.getReason());
            map.put("speciality",message.getSpeciality());
            for(Object object : map.entrySet()){
                Map.Entry<String,String> entry = (Map.Entry<String,String>) object;
                buildTextField(acroForm,defaultAppearance,entry.getKey(),entry.getValue());
            }

        }
    }

    /**
     * 构建文本域数据
     * @param acroForm 文档表单
     * @param simfangDefaultAppearance 文本 默认外观（字体 字号）
     * @param key 文本域key值
     * @param value 文本域value数据
     * @throws IOException
     */
    private static void buildTextField(PDAcroForm acroForm, String simfangDefaultAppearance, String key, String value) throws IOException {

        // 根据key获取文本域
        PDTextField date = (PDTextField) acroForm.getField(key);
        // 给文本域添加默认外观
        date.setDefaultAppearance(simfangDefaultAppearance);
        // 文本域赋值
        date.setValue(value);

    }



    /**
     * 配置志愿服务
     * @param pdfDocument 文档
     * @param allVolunteers 所有志愿服务
     * @param pickVolunteers 所有选中的志愿服务
     * @throws IOException
     */
    private static void buildAllVolunteers(PDDocument pdfDocument, Map<String, List<DictData>> allVolunteers, List<String> pickVolunteers ) throws IOException {
        if(allVolunteers.isEmpty() || CollectionUtils.isEmpty(pickVolunteers)){
            return;
        }
        int xAllApp = PdfBoxConfig.START_TEXT_X_220;
        int xllAvailable = PdfBoxConfig.START_TEXT_X_280;
        int yAll = PdfBoxConfig.START_TEXT_Y_600;
        int lineSpacing = PdfBoxConfig.LINE_SPACING;

        for (Map.Entry<String, List<DictData>> entry : allVolunteers.entrySet()) {

            showText(pdfDocument, entry.getKey() + ":", xAllApp, yAll ,false);
            List<DictData> value = entry.getValue();
            if(CollectionUtils.isEmpty(value)){
                yAll = yAll - lineSpacing;
                continue;
            }

            String available = "";
            for(DictData DictData : value){
                available = available + PdfBoxConfig.CHECK_BOX + DictData.getDictValue() + "   ";
                // 判断是否换行
                if(available.length() > PdfBoxConfig.LINE_LONG){
                    yAll = yAll - lineSpacing;
                    xllAvailable = PdfBoxConfig.START_TEXT_X_280;
                    available = "";
                }
                // 添加复选框
                if(pickVolunteers.contains(DictData.getDictName())){
                    showText(pdfDocument, PdfBoxConfig.CHECK_BOX, xllAvailable, yAll,true);
                } else {
                    showText(pdfDocument, PdfBoxConfig.UN_CHECK_BOX, xllAvailable, yAll,true);
                }
                xllAvailable = xllAvailable + PdfBoxConfig.SYMBOL_TEXT;
                // 添加文本
                showText(pdfDocument, DictData.getDictValue() + "  ", xllAvailable, yAll, false);
                xllAvailable = xllAvailable + DictData.getDictValue().length() * 4 + PdfBoxConfig.TEXT_SYMBOL;
            }

            // 换行
            yAll = yAll - lineSpacing;
            xllAvailable = PdfBoxConfig.START_TEXT_X_280;
        }
    }

    /**
     * 配置类型
     * @param pdfDocument 文档
     * @param volunteerType 当前类型
     * @param dictData 所有类型数据
     * @throws IOException
     */
    private static void buildVolunteerTypes(PDDocument pdfDocument, String volunteerType, List<DictData> dictData) throws IOException {
        if(CollectionUtils.isEmpty(dictData) || null == volunteerType){
            return;
        }
        // 换行位置
        int lineBreak = dictData.size() / 2 + dictData.size() % 2;
        int i = 1;
        // text绝对位置
        int x = PdfBoxConfig.START_TEXT_X_220;
        int y = PdfBoxConfig.START_TEXT_Y_720;

        for(DictData data : dictData){
            if(volunteerType.equals(data.getDictName())){
                showText(pdfDocument, PdfBoxConfig.CHECK_BOX, x, y,true);
            } else {
                showText(pdfDocument, PdfBoxConfig.UN_CHECK_BOX, x, y,true);
            }
            x = x + PdfBoxConfig.SYMBOL_TEXT;
            showText(pdfDocument, data.getRemark(), x, y, false);
            x = x + PdfBoxConfig.TEXT_TEXT;

            if(lineBreak == i){
                x = PdfBoxConfig.START_TEXT_X_220;
                y = y - PdfBoxConfig.LINE_SPACING;
            }
            i++;
        }
    }

    /**
     * 特殊复选框
     * @param pdfDocument 文档
     * @throws IOException
     * @throws DocumentException
     */
    private static void buildCheckBox(PDDocument pdfDocument) throws IOException {

        showText(pdfDocument, PdfBoxConfig.UN_CHECK_BOX, PdfBoxConfig.START_TEXT_X_213, PdfBoxConfig.START_TEXT_Y_405, true);

        // Service Account Name 默认no
        showText(pdfDocument, PdfBoxConfig.UN_CHECK_BOX, PdfBoxConfig.START_TEXT_X_366, PdfBoxConfig.START_TEXT_Y_405, true);
    }

    /**
     * 添加文本 或 符号
     * @param pdfDocument 文档
     * @param txt 待添加的文本
     * @param x 绝对位置x
     * @param y 绝对位置y
     * @param isSymbol 是否是符号
     * @throws IOException
     */
    public static void showText(PDDocument pdfDocument, String txt, float x, float y, Boolean isSymbol)  throws IOException {

        // 获取所需页面
        PDPage page = pdfDocument.getPage(0);

        // 准备内容流
        PDPageContentStream contentStream = new PDPageContentStream(pdfDocument, page,
                PDPageContentStream.AppendMode.PREPEND, false);

        // 字体
        if(isSymbol){
            // 特殊复选框框符号字体
            InputStream seguisym = new ClassPathResource(FONT_SEGUISYM).getInputStream();
            PDFont seguisymFont = PDType0Font.load(pdfDocument, seguisym);
            contentStream.setFont(seguisymFont, 10);
        } else {
            // 中文
            InputStream inputStream = new ClassPathResource(FONT_SIMHEI).getInputStream();
            PDFont seguisymFont = PDType0Font.load(pdfDocument, inputStream);
            contentStream.setFont(seguisymFont, 10);
            // 普通英文字体
            //contentStream.setFont(PDType1Font.HELVETICA, 9);
        }

        // 开始写入文本
        contentStream.beginText();

        // 文本位置
        contentStream.newLineAtOffset(x, y);

        // 文本内容
        contentStream.showText(txt);

        // 结束写入文本
        contentStream.endText();

        // 关闭内容流
        contentStream.close();

    }
}
